// 这是一个基于创建进程链的程序，且原始进程可以在创建子进程前打开文件。
// 每个子进程都会将消息写入文件而不是标准错误中：每条消息都分两部分写入。
// 由于进程共享系统文件表中的一个条目，因此它们共享文件偏移量。
// 每次进程写入文件时，文件偏移量就会被更新

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>

#define BUFSIZE 1024
#define CREATE_FLAGS (O_WRONLY | O_CREAT | O_TRUNC)
#define CREATE_PERMS (S_IRUSR | S_IWUSR | S_IROTH)

// argv[1]用来指针进程链的数量, argv[2]用来指针文件名称
int main(int argc, char *argv[]){
    char buf[BUFSIZE];
    pid_t childpid = 0;
    int fd;
    int i, n;

    // 检查有效的命令行参数数量
    if (argc != 3) {
        fprintf(stderr, "Usage: %s processes filename\n", argv[0]);
        return 1;
    }

    // 在fork前打开日志目录
    fd = open(argv[2], CREATE_FLAGS, CREATE_PERMS);
    if (fd < 0) {
        perror("Failed to open file");
        return -1;
    }
    fprintf(stderr, "file open successful\n");
    // 创建一个进程链
    n = atoi(argv[1]);      // argv[1]用来指针进程链的数量
    for (i = 1; i <= n; i++) {
        if (childpid = fork()) {    // 此时子进程会继续创建子子进程，而父进程会break跳出for循环
            break;
        }
    }
    if (childpid == -1) {
        perror("Failed to fork");
        return -1;
    }

    // 对普通日志进行两次写操作
    sprintf(buf, "i: %d process: %ld ", i, (long)getpid());
    write(fd, buf, strlen(buf));
    
    sleep(1);
    sprintf(buf, "parent: %ld;  child: %ld\n", (long)getppid(), (long)childpid);
    write(fd, buf, strlen(buf));

    printf("%d process write over\n", i);
    return 0;
}